home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 20
/
Cream of the Crop 20 (Terry Blount) (1996).iso
/
os2
/
bind493a.zip
/
named
/
ns_validate.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-08
|
32KB
|
1,246 lines
/**************************************************************************
* ns_validate.c (was security.c in original ISI contribution)
* author: anant kumar
* contributed: March 17, 1993
*
* implements validation procedure for RR's received from a server as a
* response to a query.
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <errno.h>
#include <stdio.h>
#include <resolv.h>
#include "named.h"
#ifdef VALIDATE
static int isvalid __P((struct namebuf *, int, int, char *, int)),
check_addr_ns __P((struct databuf **,
struct sockaddr_in *,
char *)),
check_in_tables __P((struct databuf **,
struct sockaddr_in *,
char *));
#if 0
static void stick_in_queue __P((char *, int, int, char *));
#endif
static NAMEADDR nameaddrlist[MAXNAMECACHE];
static int firstNA = 0,
lastNA = 0;
static TO_Validate *validateQ, *currentVQ;
static int VQcount;
/*****************************************************************
* validate() is called from dovalidate(). it takes as parameters,
* the domain name sought, the class, type etc. of record, the server
* that gave us the answer and the data it gave us
*
* it returns VALID if it is able to validate the record, INVALID if it cannot.
* furtehr VALID is split into VALID_CACHE if we need to cache this record
* since the domainname is not something we are authoritative for and
* VALID_NO_CACHE if the name is something we are authoritative for.
*
* pseudocode for function validate is as follows:
* validate(domain, qdomain, server, type, class, data, dlen, rcode) {
*
* if (dname or a higher level name not found in cache)
* return INVALID;
* if (NS records for "domain" found in cache){
*
* if (we are authoritative) /findns() returned NXDOMAIN;/
* if (we did not have an exact match on names)
* =>the name does not exist in our database
* => data is bad: return INVALID
* if (data agrees with what we have)
* return VALID_NO_CACHE;
* else return INVALID;
*
* if (we are not authoritative) /findns() returned OK;/
* if (domain lives below the qdomain)
* return VALID_CACHE;
* if (address records for NS's found in cache){
* if ("server" = one of the addresses){
* return VALID_CACHE;
* }else{
* stick in queue of "to_validate" data;
* return (INVALID);
* }
* else return INVALID;
*
* This performs the validation procedure described above. Checks
* for the longest component of the dname that has a NS record
* associated with it. At any stage, if no data is found, it implies
* that the name is bad (has an unknown domain identifier) thus, we
* return INVALID.
* If address of one of these servers matches the address of the server
* that returned us this data, we are happy!
*
* since findns will set needs_prime_cache if np = NULL is passed, we always
* reset it. will let ns_req do it when we are searching for ns records to
* query someone. hence in all the three cases of switch(findns())
* we have needs_prime_cache = 0;
*****************************************************************************/
int
validate(dname, qdomain, server, type, class, data, dlen
#ifdef NCACHE
,rcode
#endif
)
char *dname, *qdomain;
struct sockaddr_in *server;
int type, class;
char *data;
int dlen;
#ifdef NCACHE
int rcode;
#endif
{
struct namebuf *np, *dnamep;
struct hashbuf *htp;
struct databuf *nsp[NSMAX];
int count;
const char *fname;
int exactmatch = 0;
struct fwdinfo *fwd;
#ifdef DATUMREFCNT
nsp[0] = NULL;
#endif
dprintf(3, (ddt,
"validate(), d:%s, s:[%s], t:%d, c:%d\n",
dname, inet_ntoa(server->sin_addr), type, class));
/* everything from forwarders is the GOSPEL */
for (fwd = fwdtab; fwd != NULL; fwd = fwd->next) {
if (server->sin_addr.s_addr == fwd->fwdaddr.sin_addr.s_addr)
return (VALID_CACHE);
}
htp = hashtab;
if (priming && (dname[0] == '\0'))
np = NULL;
else
np = nlookup(dname, &htp, &fname, 0);
/* we were able to locate namebufs for this domain, or a parent domain,
* or ??? */
if (np == NULL)
fname = "";
dprintf(5, (ddt,
"validate:namebuf found np:%#lx, d:\"%s\", f:\"%s\"\n",
(u_long)np, dname, fname));
/* save the namebuf if we were able to locate the exact dname */
if (!strcasecmp(dname, fname)) {
dnamep = np;
exactmatch = 1;
}
switch (findns(&np, class, nsp, &count, 0)) {
case NXDOMAIN:
/** we are authoritative for this domain, lookup name
* in our zone data, if it matches, return valid.
* in either case, do not cache
**/
dprintf(5, (ddt, "validate: auth data found\n"));
#ifdef DATUMREFCNT
free_nsp(nsp);
#endif
if (needs_prime_cache)
needs_prime_cache = 0;
#ifdef NCACHE
if (rcode == NXDOMAIN) {
/* If we had an exactmatch on the name, we found the
* name in our authority database, so this couldn't
* have been a bad name. INVALID data, say so
*/
if (exactmatch)
return (INVALID);
else
/* we did not have an exactmatch, the data is
* good, we do not NCACHE stuff we are
* authoritative for, though.
*/
return (VALID_NO_CACHE);
}
#endif
if (!strcasecmp(dname, np->n_dname)) {
/* if the name we seek is the same as that we have ns
* records for, compare the data we have to see if it
* matches. if it does, return valid_no_cache, if it
* doesn't, invalid.
*/
if (isvalid(np, type, class, data, dlen))
return (VALID_NO_CACHE);
else
return (INVALID);
}
/* we found ns records in a higher level, if we were unable to
* locate the exact name earlier, it means we are
* authoritative for this domain but do not have records for
* this name. this name is obviously invalid
*/
if (!exactmatch)
return (INVALID);
/* we found the exact name earlier and we are obviously
* authoritative so check for data records and see if any
* match.
*/
if (isvalid(dnamep, type, class, data, dlen))
return (VALID_NO_CACHE);
else
return (INVALID);
case SERVFAIL:/* could not find name server records*/
/* stick_in_queue(dname, type, class, data); */
if (needs_prime_cache)
needs_prime_cache = 0;
#ifdef DATUMREFCNT
free_nsp(nsp);
#endif
return (INVALID);
case OK: /*proceed */
dprintf(5, (ddt, "validate:found ns records\n"));
if (needs_prime_cache)
needs_prime_cache = 0;
if (samedomain(dname, qdomain) ||
check_addr_ns(nsp, server, dname)) {
#ifdef DATUMREFCNT
free_nsp(nsp);
#endif
return (VALID_CACHE);
}
/* server is not one of those we know of */
/* stick_in_queue(dname, type, class, data); */
#ifdef DATUMREFCNT
free_nsp(nsp);
#endif
return (INVALID);
default:
#ifdef DATUMREFCNT
free_nsp(nsp);
#endif
return (INVALID);
} /*switch*/
} /*validate*/
/***********************************************************************
* validate rr returned by somebody against your own database, if you are
* authoritative for the information. if you have a record that matches,
* return 1, else return 0. validate() above will use this and determine
* if the record should be returned/discarded.
***********************************************************************/
static int
isvalid(np, type, class, data, dlen)
struct namebuf *np;
int type, class;
char *data;
int dlen;
{
register struct databuf *dp;
for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
if (!wanted(dp, class, type)) {
if ((type == T_CNAME) && (class == dp->d_class)) {
/* if a cname exists, any other will not */
return (0);
/* we come here only for zone info,
* so -ve $ed info can't be
*/
}
continue;
}
/* type and class match, if i get here
* let's now compare the data section, per RR type
*/
/* unless, of co